module RippleCarry
#(parameter WIDTH=4)
(
	input signed [WIDTH-1:0] a,
	input signed [WIDTH-1:0] b,
	input op_mode,	  // 1 for add, 0 for subtract
	input clk,    
	input cclr,
	input carry_in,
	output overflow,
	output carry_out,
	output reg [WIDTH-1:0] result
);

// internal variables
reg [WIDTH:0] a_temp;
reg [WIDTH:0] b_temp;

reg  [WIDTH:0] cin_temp; // stores carry out
reg  [WIDTH:0] result_temp;

integer i; 
integer temp;

assign overflow = (result_temp[WIDTH] ^ result_temp[WIDTH-1]) == 1 ? 1'b1 : 1'b0; 

assign carry_out = cin_temp[WIDTH]; // [WIDTH-1]'s carry out is at cin_temp[WIDTH]

always @ (a or b or carry_in ) begin
	a_temp[WIDTH:0] = {a[WIDTH-1], a[WIDTH-1:0]}; // extends a

	if (op_mode == 1) begin // add
		temp =  carry_in;
		b_temp[WIDTH:0] =  {b[WIDTH-1], b[WIDTH-1:0]}; // extends b
	end
	else begin // subtract
		temp = ~carry_in;
		b_temp[WIDTH:0] = ~{b[WIDTH-1], b[WIDTH-1:0]}; // extends b
	end

	for (i=0; i<WIDTH; i=i+1) begin  
		result_temp[i] = a_temp[i] ^ b_temp[i] ^ temp[i];
		cin_temp[i+1] = ((a_temp[i] ^ b_temp[i]) & temp) | (a_temp[i] & b_temp[i]);
		temp = cin_temp[i+1];
	end
end

always @ (posedge clk or negedge cclr) begin
	if (!cclr) begin 
		result <= 0;
	end 
	else begin 
		result[WIDTH-1:0] <= result_temp[WIDTH-1:0];
	end
end

endmodule
